package com.thinkit.bigdata.web.service.impl.bus;

import com.thinkit.bigdata.core.feature.orm.mybatis.Page;
import com.thinkit.bigdata.core.util.StringUtil;
import com.thinkit.bigdata.web.dao.bus.BusTagMapper;
import com.thinkit.bigdata.web.dao.config.SysAreaMapper;
import com.thinkit.bigdata.web.dao.config.SysStatusAttMapper;
import com.thinkit.bigdata.web.model.bus.BusTag;
import com.thinkit.bigdata.web.model.bus.BusTagExample;
import com.thinkit.bigdata.web.model.config.SysArea;
import com.thinkit.bigdata.web.model.config.SysAreaExample;
import com.thinkit.bigdata.web.model.config.SysStatusAtt;
import com.thinkit.bigdata.web.model.config.SysStatusAttExample;
import com.thinkit.bigdata.web.model.result.Constants;
import com.thinkit.bigdata.web.model.sec.TagTreeNode;
import com.thinkit.bigdata.web.service.bus.BusTagService;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

/**
 * Created by hccl on 2018/9/6.
 */
@Service
public class BusTagServiceImpl implements BusTagService {

    @Resource
    private BusTagMapper busTagMapper;

    @Resource
    private SysAreaMapper areaMapper;

    @Resource
    private SysStatusAttMapper statusAttMapper;

    @Override
    public List<BusTag> selectByExample(Page<BusTag> page, BusTagExample example) {
        // 查询出来的结果
        List<BusTag> busTagList = busTagMapper.selectByExample(page, example);
        return selectTagTypeName(busTagList);
    }

    @Override
    public List<BusTag> selectLeafByExample(Page<BusTag> page, BusTagExample example) {
        // 查询出来的结果
        List<BusTag> busTagList = busTagMapper.selectLeafByExample(page, example);
        return selectTagTypeName(busTagList);
    }

    @Override
    public List<BusTag> selectByExample(BusTagExample example) {
        List<BusTag> busTagList = busTagMapper.selectByExample(example);
        return selectTagTypeName(busTagList);
    }

    // 根据tagType查询并设置标签标识名称
    private List<BusTag> selectTagTypeName(List<BusTag> busTagList) {
        // 查询标签标识信息
        SysStatusAttExample statusAttExample = new SysStatusAttExample();
        statusAttExample.createCriteria().andTypeEqualTo(Constants.TAG_TYPE);
        List<SysStatusAtt> statusAttList = statusAttMapper.selectByExample(statusAttExample);
        Map<String, Object> tagTypeMap = new HashMap<>();
        if (statusAttList.isEmpty()) {
            tagTypeMap.put("0", "话务小结");
            tagTypeMap.put("1", "系统标签");
        } else {
            for (SysStatusAtt statusAtt : statusAttList) {
                tagTypeMap.put(statusAtt.getValue(), statusAtt.getName());
            }
        }
        // 对结果里面的tagtype进行转换
        for (BusTag busTag : busTagList) {
            // 防止数据中有标识为null的数据
            if (busTag.getTagtype() != null && tagTypeMap.get(busTag.getTagtype().toString()) != null) {
                busTag.setTagtypename(tagTypeMap.get(busTag.getTagtype().toString()).toString());
            }
        }
        return busTagList;
    }

    @Override
    public BusTag selectByPrimaryKey(Long id) {
        return busTagMapper.selectByPrimaryKey(id);
    }

    @Override
    public Integer countByExample(BusTagExample example) {
        return busTagMapper.countByExample(example);
    }

    @Override
    public Integer insertBusTag(BusTag recoord) {
        return busTagMapper.insertSelective(recoord);
    }

    @Override
    public Integer updateBusTag(BusTag recoord) {
        // 如果父级标签更新后 要考虑修改其所有子标签的内容
        int rowNum = busTagMapper.updateByPrimaryKeySelective(recoord);
        // 递归更新标签content
        recursionUpdate(recoord.getId(), recoord.getContent());
        return rowNum;
    }

    // 递归更新标签content
    private void recursionUpdate(Long parentId, String parentContent) {
        BusTagExample example = new BusTagExample();
        example.createCriteria().andParentidEqualTo(parentId);
        List<BusTag> busTagList = busTagMapper.selectByExample(example);
        for (BusTag busTag : busTagList) {
            busTag.setContent(parentContent + "-" + busTag.getName());
            busTagMapper.updateByPrimaryKeySelective(busTag);
            recursionUpdate(busTag.getId(), busTag.getContent());
        }
    }

    @Override
    public Integer deleteBusTag(Long tagId) {
        int rowNum = busTagMapper.deleteByPrimaryKey(tagId);
        recursionDelete(tagId);
        return rowNum;
    }

    @Override
    public Integer deleteBusTag(List<Long> tagIdList) {
        int rowNum = 0;
        for (Long id : tagIdList) {
            rowNum += busTagMapper.deleteByPrimaryKey(id);
            // 获取字标签递归删除
            recursionDelete(id);
        }
        return rowNum;
    }

    // 获取字标签递归删除
    private void recursionDelete(Long tagId) {
        BusTagExample example = new BusTagExample();
        example.createCriteria().andParentidEqualTo(tagId);
        List<BusTag> busTagList = busTagMapper.selectByExample(example);
        for (BusTag busTag : busTagList) {
            busTagMapper.deleteByPrimaryKey(busTag.getId());
            recursionDelete(busTag.getId());
        }
    }

    /**
     * 树的结构
     * 最顶层节点: id -10000,  text 中国电信, level 0
     * 第二层节点: id -各省份id, text 省份名称, level 1
     * 第三层节点: id 由区域id + 9999 + 标识id生成的唯一节点id, text 标签标识名称, level 2, tagType 标签标识分类 标记是哪个分类下的, areaId省份id
     * 以下各层节点为实际标签内容: id 根据标签生成的唯一节点id, text 标签名称, level 3+, tagType 标签标识分类 标记是哪个分类下的，tagId 标签标识对应的标签的tagId, areaId省份id
     *
     * @param areaId 要查询的省份 null表示全部省份
     * @return
     * @note 为保证标签标识节点id唯一 使用 区域id + 9999 + 标识id 拼接
     */
    @Override
    public TagTreeNode showTagTree(Long areaId, String tagType) {
        // 先查询出所有标识节点信息 因为所有省份都是一样的 只查询一次就可以了
        List<SysStatusAtt> tagTypeList = tagTypeInit(tagType);
        // 初始树 构建根节点信息
        TagTreeNode tagTree = new TagTreeNode();
        tagTree.setId(-10000L);
        tagTree.setText("中国电信");
        tagTree.setLevel(0);
        // 构建省份节点
        if (areaId == null) {
            SysAreaExample example = new SysAreaExample();
            example.createCriteria().andEnabledEqualTo(1);
            example.setOrderByClause("id asc");
            List<SysArea> sysAreaList = areaMapper.selectByExample(example);
            // 循环构建省份节点
            for (SysArea sysArea : sysAreaList) {
                TagTreeNode areaNode = new TagTreeNode();
                areaNode.setId(-sysArea.getId().longValue());
                areaNode.setLevel(1);
                areaNode.setText(sysArea.getArea());
                areaNode.setAreaId(sysArea.getId());
                tagTree.getChildren().add(areaNode);
                // 构建标签标识节点 同时把标签节点数据获取出来
                List<BusTag> busTagList = tagDataInit(sysArea);
                buildTypeNode(areaNode, tagTypeList, busTagList);
            }
        } else {
            // 只查询某个省份的标签信息
            SysArea sysArea = areaMapper.selectByPrimaryKey(areaId.intValue());
            if (sysArea != null) {
                // 构建省份节点
                TagTreeNode areaNode = new TagTreeNode();
                areaNode.setId(-areaId);
                areaNode.setLevel(1);
                areaNode.setText(sysArea.getArea());
                areaNode.setAreaId(sysArea.getId());
                tagTree.getChildren().add(areaNode);
                // 构建标签标识节点 同时把标签节点数据获取出来
                List<BusTag> busTagList = tagDataInit(sysArea);
                buildTypeNode(areaNode, tagTypeList, busTagList);
            }
        }
        return tagTree;
    }

    /**
     * 在省份节点下构建标签标识节点
     *
     * @param areaNode
     * @param tagTypeList
     */
    private void buildTypeNode(TagTreeNode areaNode, List<SysStatusAtt> tagTypeList, List<BusTag> busTagList) {
        // 构建标签标识节点
        for (SysStatusAtt statusAtt : tagTypeList) {
            TagTreeNode typeNode = new TagTreeNode();
            // 保证标签标识id唯一 区域id+00+标识id 从areaNode中转换出来省份id
            typeNode.setId(-Long.valueOf(Math.abs(areaNode.getId()) + "9999" + statusAtt.getId()));
            typeNode.setLevel(2);
            typeNode.setText(statusAtt.getName());
            typeNode.setTagType(Integer.valueOf(statusAtt.getValue()));
            typeNode.setAreaId((int)Math.abs(areaNode.getId()));
            areaNode.getChildren().add(typeNode);
            buildTagNode(busTagList, typeNode);
        }
    }

    /**
     * 根据标签标识的值 初始化标签树上标识节点需要显示的内容（显示所有标识分类，还是显示部分）
     *
     * @param tagType
     * @return
     */
    private List<SysStatusAtt> tagTypeInit(String tagType) {
        // 查询标签标识信息
        SysStatusAttExample statusAttExample = new SysStatusAttExample();
        SysStatusAttExample.Criteria criteria = statusAttExample.createCriteria();
        criteria.andTypeEqualTo(Constants.TAG_TYPE);
        if (StringUtil.isNotEmpty(tagType)) {
            // 如果标签标识不为null 只显示指定分类的标识，否则显示所有分类的标识
            criteria.andValueEqualTo(tagType);
        }
        List<SysStatusAtt> statusAttList = statusAttMapper.selectByExample(statusAttExample);
        if (statusAttList.isEmpty()) {
            // 防止标签标识没有配置
            SysStatusAtt att1 = new SysStatusAtt();
            // 标签id要唯一
            att1.setId(9998L);
            att1.setName("话务小结");
            att1.setValue("0");
            SysStatusAtt att2 = new SysStatusAtt();
            att2.setId(9997L);
            att2.setName("系统标签");
            att2.setValue("1");
            if ("0".equals(tagType)) {
                statusAttList.add(att1);
            } else if ("1".equals(tagType)) {
                statusAttList.add(att2);
            } else {
                // 查询所有的标识分类
                statusAttList.add(att1);
                statusAttList.add(att2);
            }
        } else {
            // 如果不是空的 手动移除值为2公用标签
            Iterator<SysStatusAtt> iterator = statusAttList.iterator();
            while (iterator.hasNext()) {
                SysStatusAtt next = iterator.next();
                if ("2".equals(next.getValue())) {
                    iterator.remove();
                }
            }
        }
        return statusAttList;
    }

    /**
     * 查询某省份下、某标识分类下的标签数据 用于后面构建标签节点
     *
     * @param area
     * @return
     */
    private List<BusTag> tagDataInit(SysArea area) {
        BusTagExample tagExample = new BusTagExample();
        BusTagExample.Criteria criteria = tagExample.createCriteria();
        criteria.andProvincecodeEqualTo(area.getCode());
        return busTagMapper.selectByExample(tagExample);
    }

    /**
     * 根据查询出来的标签集合 在标签标识节点下构建标签节点
     *
     * @param busTagList
     * @param typeNode
     */
    private void buildTagNode(List<BusTag> busTagList, TagTreeNode typeNode) {
        // 先循环把所有父类id为null的标签全取出来
        for (BusTag busTag : busTagList) {
            // 循环对比标签的标识 查询出来与节点标识一致的标签和标识为2公用的标签
            int tagType = busTag.getTagtype();
            int nodeType = typeNode.getTagType();
            if ((tagType == nodeType || tagType == 2) && busTag.getParentid() == 0) {
                TagTreeNode tagNode = new TagTreeNode();
                // 保证话务小结下标签和系统标签下相同的标签id值不同
                tagNode.setId(genTagNodeId(busTag.getId(), nodeType));
                tagNode.setLevel(3);
                tagNode.setText(busTag.getName());
                tagNode.setTagType(nodeType);// 标签节点的tagType继承标识节点的tagType
                tagNode.setTagId(busTag.getId().intValue());
                tagNode.setAreaId(typeNode.getAreaId());
                buildSubTagNode(busTagList, tagNode, nodeType);
                typeNode.getChildren().add(tagNode);
            }
        }
    }

    /**
     * 根据标签id重新生成一个树节点id（话务小结分类下的节点id为在原tagId值前加1，系统标签分类下的加2），保证树节点id唯一
     * 例如
     * 话务小结分类有一个标签 tagId为123，生成节点id就是1123，tagId为124，生成节点id就是1124；
     * 系统标签分类有一个标签 tagId为123，生成节点id就是2123，tagId为124，生成节点id就是2124；
     *
     * @param tagId
     * @param nodeType
     * @return
     */
    private Long genTagNodeId(Long tagId, Integer nodeType) {
        if (nodeType == 0) {
            return Long.valueOf("1" + tagId);
        }
        return Long.valueOf("2" + tagId);
    }

    /**
     * 在标签节点下 构建子标签节点
     *
     * @param busTagList
     * @param tagNode
     * @param nodeType   标记是哪个标识分类下
     */
    private void buildSubTagNode(List<BusTag> busTagList, TagTreeNode tagNode, int nodeType) {
        for (BusTag busTag : busTagList) {
            // 循环遍历的时候 仍然先判断标签的标识类型
            int tagType = busTag.getTagtype();
            if ((tagType == nodeType || tagType == 2) && busTag.getParentid().longValue() == tagNode.getTagId().longValue()) {
                TagTreeNode subNode = new TagTreeNode();
                subNode.setId(genTagNodeId(busTag.getId(), nodeType));
                subNode.setLevel(tagNode.getLevel() + 1);
                subNode.setText(busTag.getName());
                subNode.setTagType(nodeType);
                subNode.setTagId(busTag.getId().intValue());
                subNode.setAreaId(tagNode.getAreaId());
                tagNode.getChildren().add(subNode);
                buildSubTagNode(busTagList, subNode, nodeType);
            }
        }
    }
}
